template <typename T>
class CTask
{
protected:
    string m_strTaskName;  /** task name */
    T taskData;       /** task data */
public:
    CTask(T ptaskData):taskData(ptaskData) {}
    void SetTaskName(string taskName)
    {
        m_strTaskName = taskName;
    }
    // virtual function, define interface
    virtual int Run()= 0;

public:
    virtual ~CTask(){}
};

struct WriteSema {
    std::mutex write_mutex;
    std::condition_variable write_cond;
    bool sync_flag;
};

struct PartUploadParameters {
    bool isEndPart;
    int partNumber;
    char *contentPtr;
    long long contentLength;
    AWSS3_Object* aws_obj;
    WriteSema &writeSema;
    map<int, CompletedPart> &mapCompletedPart;
    Aws::String strUploadID;

    PartUploadParameters(int partNumber,
                        char* p_contentPtr,
                        long long contentLength,
                        AWSS3_Object* aws_obj,
                        Aws::String strUploadID,
                        bool p_IsEndPart,
                        WriteSema &pwriteSema,
                        map<int, CompletedPart> &p_mapCompletedPart): writeSema(pwriteSema), mapCompletedPart(p_mapCompletedPart) {

        this->contentPtr = (char*)calloc(MAX_SPACE_DEQUEUE, sizeof(char));
        aws_obj->m_logger(cloud_debug_all, "Out PartUploadParameters::PartUploadParameters() - partNumber=[%d] contentPtr=[%llu]", partNumber, this->contentPtr);

        this->partNumber = partNumber;
        this->contentLength = contentLength;
        memcpy(this->contentPtr, p_contentPtr, contentLength);

        isEndPart = p_IsEndPart;
        this->aws_obj = aws_obj;
        this->strUploadID = strUploadID;
    }

    void Free() {
        FREE_MEMORY(this->contentPtr);
        return ;
    }
};

bool PartUploadThread(std::shared_ptr<PartUploadParameters> ptrPartUploadParameters);

class CPartUploadTask: public CTask< std::shared_ptr<PartUploadParameters> >
{
public:
    CPartUploadTask(std::shared_ptr<PartUploadParameters> ptrPartUploadParameters):CTask< std::shared_ptr<PartUploadParameters> >(ptrPartUploadParameters)
    {
        SetTaskName("PartUploadTask");
    }

    int Run() { return 0; }

    int Run(ThreadPool< std::shared_ptr<CPartUploadTask> > *pThreadPool)
    {
        taskData->aws_obj->m_logger(cloud_debug_all, "Out CPartUploadTask::Run() - TaskName=[%s]"
            " PartUploadParameters.contentPtr=[%llu]"
            " PartUploadParameters.partNumber=[%d]"
            " PartUploadParameters.contentLength=[%lld]"
            " PartUploadParameters.strUploadID=[%s]"
            " PartUploadParameters.isEndPart=[%d]",
            m_strTaskName.c_str(),
            taskData->contentPtr,
            taskData->partNumber,
            taskData->contentLength,
            taskData->strUploadID.c_str(),
            taskData->isEndPart
            );

        // boost::atomic<bool>, don't need to be locked
        if ( taskData->contentLength )
            taskData->aws_obj->m_status = (taskData->aws_obj->m_status) ? PartUploadThread(taskData) : false;

        taskData->aws_obj->m_logger(cloud_debug_all, "Out CPartUploadTask::Run() - TaskName=[%s]"
            " PartUploadParameters.contentPtr=[%llu]"
            " PartUploadParameters.partNumber=[%d]"
            " PartUploadParameters.contentLength=[%lld]"
            " PartUploadParameters.strUploadID=[%s]"
            " PartUploadParameters.isEndPart=[%d]"
            " PartUploadThread() finished!",
            m_strTaskName.c_str(),
            taskData->contentPtr,
            taskData->partNumber,
            taskData->contentLength,
            taskData->strUploadID.c_str(),
            taskData->isEndPart
            );

        if ( taskData->isEndPart ) {

            // when counter is 1, And only this thread is running, then the all upload thread had finished.
            int counter = pThreadPool->GetRuningCounter();
            taskData->aws_obj->m_logger(cloud_debug_all, "Out CPartUploadTask::Run() - Runing Thread number is: [%d]", counter);
            while ( counter-1 ) {
                sleep(10);
                counter = pThreadPool->GetRuningCounter();
                taskData->aws_obj->m_logger(cloud_debug_all, "Out CPartUploadTask::Run() - Runing Thread number is: [%d]", counter);
            }

            {
                // reuse isEndPart to protect wait()
                std::lock_guard<std::mutex> lk(taskData->writeSema.write_mutex);
                taskData->writeSema.sync_flag = true;
            }
            taskData->aws_obj->m_logger(cloud_debug_all, "Out CPartUploadTask::Run() - taskData.isEndPart:[%d]. Will notify_one", taskData->isEndPart);
            taskData->writeSema.write_cond.notify_one();
        }

        taskData->Free();

        return 0;
    }

};
